package com.sajus.web.billing.ejb.bean;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.rmi.RemoteException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.Time;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;

import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.ToolProvider;

import org.apache.log4j.Logger;
import org.codehaus.jackson.map.util.JSONPObject;
import org.hornetq.utils.json.JSONArray;
import org.hornetq.utils.json.JSONException;
import org.hornetq.utils.json.JSONObject;

import com.sajus.billing.client.delegate.BusinessDelegateFactory;
import com.sajus.billing.client.dto.AccountDTO;
import com.sajus.billing.client.dto.DiscountDTO;
import com.sajus.billing.client.dto.OfferingDTO;
import com.sajus.billing.client.dto.PriceInfoDTO;
import com.sajus.billing.client.dto.PromoOfferingDTO;
import com.sajus.billing.client.dto.PromotionDTO;
import com.sajus.billing.client.dto.RateMappingDTO;
import com.sajus.billing.client.dto.ServiceAttributeDTO;
import com.sajus.billing.client.dto.ServiceDTO;
import com.sajus.billing.client.dto.ServiceTypeDTO;
import com.sajus.billing.client.ejb.interfaces.ServiceTypeManagerLocal;
import com.sajus.billing.client.ejb.interfaces.ServiceTypeManagerRemote;
import com.sajus.web.billing.ejb.data.model.Account;
import com.sajus.web.billing.ejb.data.model.Discount;
import com.sajus.web.billing.ejb.data.model.Offering;
import com.sajus.web.billing.ejb.data.model.PersistentObject;
import com.sajus.web.billing.ejb.data.model.PriceInfo;
import com.sajus.web.billing.ejb.data.model.PromoOffering;
import com.sajus.web.billing.ejb.data.model.Promotion;
import com.sajus.web.billing.ejb.data.model.RateMapping;
import com.sajus.web.billing.ejb.data.model.Service;
import com.sajus.web.billing.ejb.data.model.ServiceAttribute;
import com.sajus.web.billing.ejb.data.model.ServiceType;
import com.sajus.web.billing.ejb.mapper.ModelToDTOMapper;

@Stateless(mappedName = "ServiceTypeManager")
@LocalBean
@TransactionManagement( TransactionManagementType.CONTAINER )
public class ServiceTypeManagerBean extends BaseBean implements ServiceTypeManagerLocal, ServiceTypeManagerRemote  {
	
	
	private final double BYTES = 1d;
	private final double MBYTES = 1048576d;

	private final String offeringQuery = "Offering.findCurrentIndex";
	private final String promotionQuery = "Promotion.findCurrentIndex";
	private final String priceInfoQuery = "PriceInfo.findCurrentIndex";
	private final String rateMapQuery = "RateMapping.findCurrentIndex";
	private final String promoOfferingQuery = "PromoOffering.findCurrentIndex";

	private final int RECURRING = 1;
	private final int USAGE = 2;
	private final String CURRENT_USAGE = "currentUsage";

	@Override
	public ServiceTypeDTO getServiceType( Integer id) {

		ServiceType serviceType = super.getEntityByPK( ServiceType.class, id);
		if ( serviceType == null ){
			return null;
		}

		ServiceTypeDTO ret = new ServiceTypeDTO();
		ret.setDescription( serviceType.getDescription() );
		ret.setId( serviceType.getId() );
		ret.setServicecolumn( serviceType.getServicecolumn() );
		ret.setServicetable( serviceType.getServicetable() );
		ret.setType( serviceType.getType() );
		ret.setUnit( serviceType.getUnit() );

		return ret;
	}

	@Override
	public List<OfferingDTO> getOfferings( PromotionDTO arg0 ) {
		return null;
	}

	@Override
	public List<PromoOfferingDTO> getPromoOfferings(PromotionDTO promotion) {
		List<PromoOfferingDTO> ret = new ArrayList<PromoOfferingDTO>();
		if ( promotion != null ) {
			for ( PromoOfferingDTO off : promotion.getOfferings() ){
				ret.add( off );
			}
		}

		return ret;
	}

	@Override
	public List<PromotionDTO> getPromotions() {

		List<Promotion> promotions = super.getResultList("Promotion.findAll", Promotion.class );
		List<PromotionDTO> ret = new ArrayList<PromotionDTO>();

		for ( Promotion promotion : promotions ){
			ret.add( ModelToDTOMapper.map( promotion ) );
		}

		return ret;
	}

	@Override
	public List<ServiceDTO> getServices(AccountDTO acc ) {

		List<Service> services = super.getResultList( "Service.findServicesByAccount" 
				, Service.class, ModelToDTOMapper.map( acc ) );
		List<ServiceDTO> ret = new ArrayList<ServiceDTO>();
		if ( services != null ) {
			for ( Service service : services ) {
				System.out.println("getServices: service  id " + service.getId() );
				ret.add( ModelToDTOMapper.map( service ) );
			}
		}

		return ret;
	}
	
	@Override
	public List<ServiceDTO> getAllServices() {

		List<Service> services = super.getResultList( "Service.findAll" 
				, Service.class );
		List<ServiceDTO> ret = new ArrayList<ServiceDTO>();
		if ( services != null ) {
			for ( Service service : services ) {
				System.out.println("getServices: service  id " + service.getId() );
				ret.add( ModelToDTOMapper.map( service ) );
			}
		}

		return ret;
	}

	@Override
	public void saveDiscount(DiscountDTO arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void saveOffering(OfferingDTO off) {
		if ( off.getId() == null ){
			Offering saveOff =  ModelToDTOMapper.map( off );
			super.getEntityManager().merge( saveOff );
		} else {
			super.update( ModelToDTOMapper.map( off ) );
		}
	}

	@Override
	public void savePriceInfo( PriceInfoDTO pri ) {
		if ( pri.getId() == null ){
			try {
				super.persist( ModelToDTOMapper.map( pri ) );
			} catch ( Exception e ){
				e.printStackTrace();
			}
		} else {
			super.update( ModelToDTOMapper.map( pri ) );
		}
	}

	@Override
	public void savePromoOffering( PromoOfferingDTO off) {
		System.out.println("Saving Promo Offering");
		if ( off.getId() == null ){
			try {
				super.getEntityManager().merge( ModelToDTOMapper.map( off ) );
			} catch (Exception e) {
				e.printStackTrace();
			}
		} else {
			super.update( ModelToDTOMapper.map( off ) );
		}
	}

	@Override
	public void savePromotion( PromotionDTO pro ) {
		System.out.println("Promotion id " + pro.getId() );
		if ( pro.getDescription() == null ){
			return;
		}
		if ( pro.getId() == null ){
			try {
				super.getEntityManager().merge( ModelToDTOMapper.map( pro ) );
			} catch ( Exception e ){
				e.printStackTrace();
			}
		} else {
			super.update( ModelToDTOMapper.map( pro ) );
		}
	}

	@Override
	public void saveService( ServiceDTO ser ) {
		System.out.println("Service id " + ser.getId() );
		if ( ser.getId() == null ){
			try {
				super.getEntityManager().merge( ModelToDTOMapper.map( ser ) );
			} catch ( Exception e ){
				e.printStackTrace();
			}
		} else {
			super.update( ModelToDTOMapper.map( ser ) );
		}
	}

	@Override
	public void saveServiceAttribute( ServiceAttributeDTO ser ) {
		
		System.out.println("service attribute id " + ser.getId() );
		if ( ser.getService() != null ) {
			System.out.println("service id " + ser.getService().getId() );
		}
		
		try {

			super.getEntityManager().merge( ModelToDTOMapper.map( ser ) );
		} catch ( Exception e ){
			e.printStackTrace();
		}

	}

	@Override
	public void saveServiceType(ServiceTypeDTO ser) {
		System.out.println("Service Type id " + ser.getId() );
		if ( ser.getId() == null ){
			try {
				super.persist( ModelToDTOMapper.map( ser ) );
			} catch ( Exception e ){
				e.printStackTrace();
			}
		} else {
			super.update( ModelToDTOMapper.map( ser ) );
		}
	}

	@Override
	public DiscountDTO getDiscount(Integer id ) {
		return ModelToDTOMapper.map( super.getEntityByPK( Discount.class, id ) );
	}

	@Override
	public OfferingDTO getOffering(Integer id) {
		return ModelToDTOMapper.map( super.getEntityByPK( Offering.class, id) );
	}
	
	public Offering getOfferingDomain( Integer id ){
		return super.getEntityByPK( Offering.class, id);
	}

	@Override
	public PriceInfoDTO getPriceInfo(Integer id) {
		return ModelToDTOMapper.map( super.getEntityByPK( PriceInfo.class, id) );
	}

	@Override
	public PromotionDTO getPromotion(Integer id) {
		return ModelToDTOMapper.map( super.getEntityByPK( Promotion.class, id) );
	}

	@Override
	public PromoOfferingDTO getPromotionOffering(Integer id) {
		return ModelToDTOMapper.map( super.getEntityByPK( PromoOffering.class, id) );
	}

	@Override
	public ServiceDTO getService(Integer id) {
		return ModelToDTOMapper.map( super.getEntityByPK( Service.class, id) );
	}

	@Override
	public ServiceAttributeDTO getServiceAttribute(Integer id) {
		return ModelToDTOMapper.map( super.getEntityByPK( ServiceAttribute.class, id) );
	}

	public ServiceAttribute getServiceAttributeDomain(Integer id) {
		return super.getEntityByPK( ServiceAttribute.class, id);
	}
	
	@Override
	public List<OfferingDTO> getOfferings() {
		List<Offering> offerings = super.getResultList("Offering.findAll", Offering.class );
		List<OfferingDTO> ret = new ArrayList<OfferingDTO>();

		for ( Offering offering : offerings ){
			ret.add( ModelToDTOMapper.map( offering ) );
		}

		return ret;
	}

	@Override
	public List<ServiceTypeDTO> getServiceTypes() {
		List<ServiceType> serviceTypes = super.getResultList("ServiceType.findAll", ServiceType.class );
		List<ServiceTypeDTO> ret = new ArrayList<ServiceTypeDTO>();

		for ( ServiceType serviceType : serviceTypes ){
			ret.add( ModelToDTOMapper.map( serviceType ) );
		}

		return ret;
	}

	@Override
	public RateMappingDTO getRateMapping(Integer arg0) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public List<RateMappingDTO> getRateMappings() {

		System.out.println("Getting Rate Mappings ");
		List<RateMapping> rateMappings = super.getResultList("RateMapping.findAll", RateMapping.class );

		List<RateMappingDTO> ret = new ArrayList<RateMappingDTO>();

		System.out.println("Size of RateMapping = " + rateMappings.size() );

		for ( RateMapping rate : rateMappings ){
			ret.add( ModelToDTOMapper.map( rate ) );
		}

		return ret;
	}

	@Override
	public void saveRateMapping(RateMappingDTO rate) {
		if ( rate.getId() == null ){
			rate.setId( generateIDNumber( rateMapQuery, RateMapping.class) );
			super.getEntityManager().merge( ModelToDTOMapper.map( rate ) );
		}
		super.update( ModelToDTOMapper.map( rate ) );
	}

	private int generateIDNumber(String query, Class cls) {
		PersistentObject ser = super.getSingleResult(query, cls );

		if ( ser == null ){
			System.out.println("Table was empty " + cls.toString() );
			return 1;
		} else {
			return ser.getId() + 1;
		}
	}

	private void preBillingScript(){

		JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

		Iterable<? extends JavaFileObject> fileObjects;

		String url = "jdbc:mysql://localhost:3306/domain1";
		String user = "bpm";
		String password = "bpm22";
		ResultSet result = null;
		ResultSet result2 = null;
		Connection con = null;

		try {

			con = DriverManager.getConnection(url, user, password);
			Statement st = (Statement) con.createStatement();

			String preBillScript = "SELECT * FROM javaRunTimeCompile";
			result = st.executeQuery( preBillScript );

			String program = "";

			while ( result.next() ){
				int id = result.getInt( "id" );
				if ( id == 1 ){
					program = result.getString( "script" );
				}
			}

			fileObjects = getJavaSourceFromString(program);
			compiler.getTask(null, null, null, null, null, fileObjects).call();

			Class<?> clazz = Class.forName("PreBillScript");
			Method m = clazz.getMethod("preBillingScript", new Class[] {  } );
			m.invoke(null, null);

		} catch ( Exception e ){
			e.printStackTrace();
		}

	}

	static Iterable<JavaSourceFromString> getJavaSourceFromString(String code) {
		final JavaSourceFromString jsfs;
		jsfs = new JavaSourceFromString("code", code);
		return new Iterable<JavaSourceFromString>() {
			public Iterator<JavaSourceFromString> iterator() {
				return new Iterator<JavaSourceFromString>() {
					boolean isNext = true;

					public boolean hasNext() {
						return isNext;
					}

					public JavaSourceFromString next() {
						if (!isNext)
							throw new NoSuchElementException();
						isNext = false;
						return jsfs;
					}

					public void remove() {
						throw new UnsupportedOperationException();
					}
				};
			}
		};
	}

	private List<Account> getAccounts(){
		List<Account> accounts = super.getResultList("Account.findAll", Account.class );
		return accounts;
	}
	
	@Override
	public void doUsageBilling() {

//		preBillingScript();

		String url = "jdbc:mysql://localhost:3306/domain1";
		String user = "bpm";
		String password = "bpm22";
		ResultSet result = null;
		ResultSet result2 = null;
		Connection con = null;

		try {
			con = DriverManager.getConnection(url, user, password);
			Statement st = (Statement) con.createStatement(); 

			//get each account;

			//Get account list:
			List<Account> accounts = getAccounts();

			if ( accounts == null ){
				return;
			}

			for ( Account account : accounts ) {

				// Get list of services
				Set<Service> services = account.getServices();
				List<ServiceAttribute> tmpStates = new ArrayList<ServiceAttribute>();
				
				for ( Service service : services ){
					
					if ( service.getOffering().getServiceType() != null 
							&& service.getOffering().getServiceType().getType() != null
							&& service.getOffering().getServiceType().getType().intValue() == USAGE ){

						String identifier = service.getOffering().getServiceType().getIdentifier();
						List<ServiceAttribute> sas = service.getServiceAttributes();

						String tableName = service.getOffering().getServiceType().getServicetable();
						String columnName = service.getOffering().getServiceType().getServicecolumn();
						String serviceId = service.getOffering().getServiceType().getIdentifier();
						String channelId = service.getOffering().getServiceType().getChannelId();

						String usageId = null;
						ServiceAttribute usageAtt = null;

						double limit = service.getOffering().getLimits();
						double currentUsage = 0d;

						if ( service.getLimitsUsage() != 0d ){
							limit = service.getLimitsUsage();
						}

						for ( ServiceAttribute sa : sas ) {
							if ( sa.getName() != null && sa.getName().equals( channelId ) ){
								usageId = sa.getValue();
							}

							if ( sa.getName() != null && sa.getName().equalsIgnoreCase( CURRENT_USAGE ) ){
								usageAtt = getServiceAttributeDomain( sa.getId() );
								currentUsage = Double.parseDouble( sa.getValue() );
							}
						}

						String smsUseSql = "SELECT * FROM " + tableName
								+ " WHERE " + serviceId + " = '" 
								+ usageId + "'";

						Statement st3 = con.createStatement();
						ResultSet usageDetailsSet = st3.executeQuery( smsUseSql );

						while ( usageDetailsSet.next() ){

							int usageID = usageDetailsSet.getInt( "id" );

							// Case where current usage will just pass monthly limit

							if ( columnName == null ) {
								
								updateSimRate( service, usageID, "", currentUsage);
								
							} else {

								double usageAmt = usageDetailsSet.getInt( columnName );
								
								//Thomas Li - Set the units from service types
								if ( columnName.equals( "bytes" ) ){
									usageAmt = usageAmt / MBYTES;
								}
								
								updateSimRate( service, usageID, "", usageAmt, currentUsage );
								currentUsage = currentUsage + usageAmt;

							}
						} 
						if ( usageAtt != null ) {
							usageAtt.setValue( currentUsage + "" );
							tmpStates.add( usageAtt );
						}
						
						String sql = "UPDATE " + service.getOffering().getServiceType().getServicetable() 
								+ " SET charged_date = curdate() WHERE charged_date is NULL AND charge is not null ";
						st.executeUpdate( sql );

					}
				}
				
				for ( ServiceAttribute sa : tmpStates ){
					super.getEntityManager().merge( sa );
				}
				
			}
			con.close();
		} catch ( Exception e ){
			e.printStackTrace();
		}
	}

	private void updateSimRate(Service service, int usageId, String rateKey, double currentUsage ) {
		updateSimRate(service, usageId, rateKey, 0.0, currentUsage );
	}

	private void updateSimRate(Service service, 
			int usageId, String rateKey, 
			double usage, double currentUsage ) {
		Connection con = null;

		try {
			String url = "jdbc:mysql://localhost:3306/domain1";
			String user = "bpm";
			String password = "bpm22";

			con = DriverManager.getConnection(url, user, password);
			Statement st = (Statement) con.createStatement(); 

			double totalUsage = usage + currentUsage; 
			//			String rateMapping = "SELECT * FROM ratemapping where rateKey = '" + rateKey +"'";
			//			ResultSet rateRs = st.executeQuery( rateMapping );

			// get Rate from offering or service
			double rate = 0d;
			double charge = 0d;
			double limit = service.getOffering().getLimits();

			if ( service.getLimitsUsage() != 0d ){
				limit = service.getLimitsUsage();
			}

			double step1unit = service.getOffering().getStep1Unit();
			if ( service.getStep1Unit() != 0d ){
				step1unit = service.getStep1Unit();
			}
			
			if ( step1unit <= 0 ){
				step1unit = Double.MAX_VALUE;
			}

			double step2unit = service.getOffering().getStep2Unit();
			if ( service.getStep2Unit() != 0d ){
				step2unit = service.getStep2Unit();
			}
			if ( step2unit <= 0 ){
				step2unit = Double.MAX_VALUE;
			}

			if ( totalUsage <= limit ){

				charge = 0d;

			} else if ( totalUsage > limit && currentUsage < limit ){
				double less = limit - currentUsage;
				double more = usage - less;

				rate = service.getOffering().getBaseRate();
				if ( service.getBaseRate() != 0d ){
					rate = service.getBaseRate();
				}
				
				charge = charge + ( rate * more );


			} else if ( currentUsage > limit && totalUsage < step1unit ) {

				rate = service.getOffering().getBaseRate();
				if ( service.getBaseRate() != 0d ){
					rate = service.getBaseRate();
				}
				
				charge = charge + ( rate * usage );

			} else if ( currentUsage < step1unit && totalUsage > step1unit ){

				// Overflow step 2 units
				double less = step2unit - currentUsage;
				double more = usage - less;

				rate = service.getOffering().getBaseRate();
				if ( service.getBaseRate() != 0d ){
					rate = service.getBaseRate();
				}
				
				charge = charge + (rate * less);

				rate = service.getOffering().getStep1Rate();
				if ( service.getStep1Rate() != 0d ){
					rate = service.getStep1Rate();
				}
				
				charge = charge + (rate * more);

			} else if ( currentUsage > step1unit && totalUsage < step2unit ){

				rate = service.getOffering().getStep1Rate();
				if ( service.getStep1Rate() != 0d ){
					rate = service.getStep1Rate();
				}
				
				charge = charge + ( rate * usage );

			}  else if ( currentUsage < step2unit && totalUsage > step2unit ){

				// Overflow step 2 units
				double less = step2unit - currentUsage;
				double more = usage - less;

				rate = service.getOffering().getStep1Rate();
				if ( service.getStep1Rate() != 0d ){
					rate = service.getStep1Rate();
				}
				
				charge = charge + (rate * less);

				rate = service.getOffering().getStep2Rate();
				if ( service.getStep2Rate() != 0d ){
					rate = service.getStep2Rate();
				}
				

				charge = charge + (rate * more);
			} else if ( currentUsage > step2unit ){

				rate = service.getOffering().getStep2Rate();
				if ( service.getStep2Rate() != 0d ){
					rate = service.getStep2Rate();
				}
				
				charge = charge + ( rate * usage );
			}

			String table = service.getOffering().getServiceType().getServicetable();

			if ( service.getOffering().getServiceType().getServicecolumn() == null ){
				String sql = "UPDATE " + table + " SET charge = " + charge + " WHERE id = " + usageId;
				st.executeUpdate(sql);
			} else {
				String sql = "UPDATE " + table + " SET charge = " + charge + " WHERE id = " + usageId;
				st.executeUpdate(sql);
			}
			
		} catch (Exception e ){
			Logger.getLogger( ServiceTypeManagerBean.class ).error( "Failed to update sim " + e.getMessage() );
		} finally {
			try {
				con.close();
			} catch ( Exception e ){
				Logger.getLogger( ServiceTypeManagerBean.class ).error( "Failed to close connection ");
			}
		}

	}

	private final String AUTH_ENDPOINT = "http://s1.trootrax.com/rest/v0.9/auth/sessions";
	private final String USER = "user=billing_ops";
	private final String PW = "pw=h62PzLmuA15WUiW";
	private final String REALM = "realm=production";
	
	private final String ACTIVATION_ENDPOINT = "http://s1.trootrax.com/rest/v0.9/tracking/provisioning/devices/events";
	private final String PROVISIONING_ENDPOINT = "http://s1.trootrax.com/rest/v0.9/tracking/provisioning/devices/";
	private final String CHANNEL_ENDPOING = "/channels";
	
	private final String DEVICE_TYPE = "type=ACTIVATED";
	private final String DEVICE_NAME = "DeviceID";
	private final String CHANNEL_ID = "ChannelID";
	private final String DEVICE_ESN = "DeviceESN";
	private final String CURRENT_USAGE_NAME = "currentUsage";
	
	@Override
	public void getActivateDevices() {
		List<ServiceAttribute> sAtts = getServiceAttributes();
		
		try {
			String key = getSessionKey();
			// Fetch list of devices
			String deviceListObj = getDevicesActivated( key );
			JSONArray parentList = new JSONArray( deviceListObj );
			JSONArray objList = parentList.getJSONArray( 0 );
			for(int i = 0; i < objList.length(); i++)
			{
				
				
				JSONObject objects = objList.getJSONObject( i );
				String device_id = objects.getString( "device_id" );
				String customer = objects.getString( "customer" );
				String domain = objects.getString( "domain" );
				String esn = objects.getString( "esn" );
				String channelId = null;
				
				try {
					channelId = getChannelId( key, device_id );
				} catch ( Exception e ) {
					
				}
				
				boolean deviceExists = false;
				for (ServiceAttribute sa : sAtts ){
					if ( sa.getName().equals( DEVICE_NAME )
							&& sa.getValue().equals( device_id ) ) {
						deviceExists = true;
					}
				}
				
				if ( deviceExists ) {
					continue;
				}

				// Create a new Service
				Service service = new Service();
				
				List<ServiceAttribute> saList = new ArrayList<ServiceAttribute>();
				
				// Create a new Service Attribute 
				ServiceAttribute deviceAttribute = new ServiceAttribute();
				deviceAttribute.setName( DEVICE_NAME );
				deviceAttribute.setValue( device_id );
				deviceAttribute.setService( service );
				saList.add( deviceAttribute );
				
				// Create a new Service Attribute 
				ServiceAttribute esnAttribute = new ServiceAttribute();
				esnAttribute.setName( DEVICE_ESN );
				esnAttribute.setValue( esn );
				esnAttribute.setService( service );
				saList.add( esnAttribute );
				
				
				ServiceAttribute channelIdAttribute = null;
				
				if ( channelId != null ) {
					channelIdAttribute = new ServiceAttribute();
					channelIdAttribute.setName( CHANNEL_ID );
					channelIdAttribute.setValue( channelId );
					channelIdAttribute.setService( service );
					saList.add( channelIdAttribute );
					
					// Create a new Service Attribute currentUsage
					ServiceAttribute curUsage = new ServiceAttribute();
					curUsage.setName( CURRENT_USAGE_NAME );
					curUsage.setValue( "0.0" );
					curUsage.setService( service );
					saList.add( curUsage );
				}
				
				System.out.println( "Channel id " + channelId + " device id " + device_id );
				
				// look for the account
				Account account = null;
				List<Account> accounts = getAccounts();
				for ( Account acc : accounts ){
					if ( customer != null
							&& customer.equals( acc.getCompany() ) ) {
						account = acc;
					}
				}
				
				if ( account == null ){
					// Create a new Account
					account = createNewAccount( customer );
				}
				
				// look for the parent account
				accounts = getAccounts();
				for ( Account acc : accounts ){
					if ( domain != null
							&& domain.equals( acc.getCompany() ) ) {
						account.setParent( acc );
					}
				}
				if ( account.getParent() == null ) {
					// Create a new Parent Account
					Account parent = createNewAccount( domain );
					account.setParent( parent );
				}
				
				// set service to account;
				service.setAccount( account );
				service.setStatus( 1 );
				service.setOffering( getOfferingDomain( 17 ) ); // set the offering to default
				service.setBaseRate( 0.0 );
				service.setLimitsUsage( 0.0 );
				service.setStep1Rate( 0.0 );
				service.setStep1Unit( 0.0 );
				service.setStep2Rate( 0.0 );
				service.setStep2Unit( 0.0 );
				service.setMaxRate( 0.0 );
				service.setMaxUnit( 0.0 );
				service.setMinRate( 0.0 );
				service.setMinUnit( 0.0 );
				service.setServiceAttributes( saList );
				
				super.getEntityManager().merge( service );
				
			}
			
			// Remove accounts that parents to themselves:
			List<Account> accounts = getAccounts();
			for ( Account acc : accounts ){
				if ( acc.getParent() != null ) {
					if ( acc.getParent().getId() == acc.getId() ){
						acc.setParent( null );
						super.getEntityManager().merge( acc );
					}
				}
			}
			
		} catch ( Exception e ) {
			e.printStackTrace();
		}
		
		
	}
	
	private List<ServiceAttribute> getServiceAttributes() {
		List<ServiceAttribute> ret = super.getResultList("ServiceAttribute.findAll", ServiceAttribute.class );
		return ret;
	}

	private String getSessionKey() throws IOException, JSONException {
		URL url = new URL( AUTH_ENDPOINT + "?" + USER + "&" + PW + "&" + REALM );
		HttpURLConnection con = (HttpURLConnection) url.openConnection();
		
		con.setRequestMethod( "POST" );
		con.setDoOutput( true );
		con.getResponseCode();
		
		BufferedReader in = new BufferedReader( new InputStreamReader( con.getInputStream() ) );
		String inputLine;
		StringBuffer response = new StringBuffer();
 
		while ( ( inputLine = in.readLine() ) != null ) {
			response.append( inputLine );
		}
		
		in.close();
		JSONObject jsonSession = new JSONObject( response.toString() );
		
		return "key=" + jsonSession.getString( "key" );
	}
	
	
	private String getDevicesActivated( String key ) throws IOException{
		
		//"http://s1.trootrax.com/rest/v0.9/tracking/provisioning/devices/events?key=52658effff288d6dbf000001&type=ACTIVATED&from=2013-10-01&to=2013-10-17"
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		
		Calendar yes = Calendar.getInstance();
		yes.add( Calendar.MONTH, -1);
		
		String fromDate = "from=" + df.format( yes.getTime() );
		String toDate = "to=" + df.format( new Date() );
		URL url= new URL( ACTIVATION_ENDPOINT + "?" + key + "&" + DEVICE_TYPE + "&" + fromDate + "&" + toDate );
		HttpURLConnection con= (HttpURLConnection) url.openConnection();
		
		con.setRequestMethod( "GET" );
		con.setDoOutput( true );
		con.getResponseCode();
		
		BufferedReader in = new BufferedReader( new InputStreamReader( con.getInputStream() ) );
		String inputLine;
		StringBuffer response = new StringBuffer();
 
		while ( ( inputLine = in.readLine() ) != null ) {
			response.append( inputLine );
		}
		in.close();
		
		return response.toString();
	}
	
	private String getChannelId( String key, String device ) throws IOException, JSONException {
		
		URL url= new URL( PROVISIONING_ENDPOINT + device + CHANNEL_ENDPOING + "?" + key );
		HttpURLConnection con= (HttpURLConnection) url.openConnection();
		
		con.setRequestMethod( "GET" );
		con.setDoOutput( true );
		con.getResponseCode();
		
		BufferedReader in = new BufferedReader( new InputStreamReader( con.getInputStream() ) );
		String inputLine;
		StringBuffer response = new StringBuffer();
 
		while ( ( inputLine = in.readLine() ) != null ) {
			response.append( inputLine );
		}
		in.close();
		
		JSONArray parentList = new JSONArray( response.toString() );
		JSONObject jsonObj = parentList.getJSONObject( 0 );
		
		return jsonObj.getString( "iccid" );
	}
	
	public Account createNewAccount( String customer ){
		Account account = new Account();
		account.setCompany( customer );
		account.setAddressSameOnCreditCard( false );
		account.setBillingPeriodType( "Monthly" );
		account.setBillingDay( 1 );
		account.setBillingTime( new Time( 0 ) );
		account.setBillingPeriodStartDay( 1 );
		account.setBillingPeriodStartTime( new Time( 0 ) );
		
		Calendar nextBillingDate = Calendar.getInstance();
		nextBillingDate.add( Calendar.MONTH, 1 );
		nextBillingDate.set( Calendar.DAY_OF_MONTH, nextBillingDate.getActualMinimum( Calendar.DAY_OF_MONTH) );
		account.setNextBillingDate( nextBillingDate.getTime() );
		account.setStatus( 1 );
		account.setType( 1 );
		account.setPayByCreditCard( false );
		account.setMailInvoice( false );
		
		return account;
	}
	
	
}



class JavaSourceFromString extends SimpleJavaFileObject {
	final String code;

	JavaSourceFromString(String name, String code) {
		super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
		this.code = code;
	}

	public CharSequence getCharContent(boolean ignoreEncodingErrors) {
		return code;
	}

}

/**
 * {
 * "esn":"012605001282104",
 * "activated":"2013-11-04T10:05:12",
 * "domain":"tracking",
 * "cluster":3,
 * "device_id":19094,
 * "type":"enfora_spidermt",
 * "customer":"Demo"
 * }
 * 
 */

